home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / devScsiDevice.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  21KB  |  711 lines

  1. /* 
  2.  * devScsiDevice.c --
  3.  *
  4.  *    Routines for attaching/releasing/sending commands to SCSI device 
  5.  *    attached to SCSI HBAs.
  6.  *
  7.  * Copyright 1989 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/devScsiDevice.c,v 9.12 91/12/11 17:58:58 jhh Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include <sprite.h>
  22. #include <scsiDevice.h>
  23. #include <scsiHBA.h>
  24. #include <dev/scsi.h>
  25. #include <sys/scsi.h>
  26. #include <devQueue.h>
  27. #include <fs.h>
  28. #include <sync.h>
  29. #include <stdlib.h>
  30. #include <bstring.h>
  31.  
  32. static int scsiDoneProc _ARGS_((struct ScsiCmd *scsiCmdPtr, 
  33.             ReturnStatus status, int statusByte, 
  34.             int byteCount, int senseLength, Address senseDataPtr));
  35.  
  36.  
  37. /*
  38.  *----------------------------------------------------------------------
  39.  *
  40.  * DevScsiAttachDevice --
  41.  *
  42.  *    Return a handle that allows access to the specified SCSI device.
  43.  *
  44.  * Results:
  45.  *    A pointer to the ScsiDevice structure for the device. 
  46.  *    NIL if the device could not be attached.
  47.  *
  48.  * Side effects:
  49.  *    If the device is attached, an INQUIRY command is sent to the 
  50.  *    device.
  51.  *
  52.  *----------------------------------------------------------------------
  53.  */
  54.  
  55. ScsiDevice   *
  56. DevScsiAttachDevice(devicePtr, insertProc)
  57.     Fs_Device    *devicePtr;    /* Device to attach. */
  58.     void     (*insertProc)(); /* Insert procedure to use. */
  59. {
  60.     int     hbaType;    
  61.     ScsiDevice   *handle;
  62.     ScsiCmd    inquiryCmdBlock;
  63.  
  64.     /*
  65.      * Call the Attach procedure for the HBA type specified in the Fs_Device.
  66.      */
  67.     hbaType = SCSI_HBA_TYPE(devicePtr);
  68.  
  69.     if (hbaType >= devScsiNumHBATypes) {
  70.     handle = (ScsiDevice *) NIL;
  71.     } else {
  72.     handle = (devScsiAttachProcs[hbaType])(devicePtr,insertProc);
  73.     /*
  74.      * The attach routines bzero the handle and only fill in some
  75.      * of the fields.  The rest of the kernel assumes that errorProc
  76.      * is either points to a routine or it is NIL.  Take care of it
  77.      * here.
  78.      */
  79.     if ((handle != (ScsiDevice *) NIL) &&
  80.         (handle->errorProc == (ReturnStatus (*)()) 0)) {
  81.         handle->errorProc = (ReturnStatus (*)()) NIL;
  82.     }
  83.     }
  84.     /*
  85.      * If the inquiry data doesn't exists for this device yet send the
  86.      * device a INQUIRY command. We try it twice because the device might
  87.      * abort the INQUIRY with a UNIT_ATTENTION.
  88.      */
  89.     if ((handle != (ScsiDevice *) NIL) && (handle->inquiryLength == 0)) {
  90.     int    tryNumber = 1;
  91.     ReturnStatus    status = SUCCESS;
  92.  
  93.     while((tryNumber <= 2) && (handle->inquiryLength == 0) && 
  94.           (status != DEV_TIMEOUT)) { 
  95.         if (handle->inquiryDataPtr == (char *) 0) {
  96.         handle->inquiryDataPtr = (char *) malloc(DEV_MAX_INQUIRY_SIZE);
  97.         }
  98.         (void) DevScsiGroup0Cmd(handle,SCSI_INQUIRY,0,DEV_MAX_INQUIRY_SIZE,
  99.                     &inquiryCmdBlock);
  100.         inquiryCmdBlock.buffer = handle->inquiryDataPtr;
  101.         inquiryCmdBlock.bufferLen = DEV_MAX_INQUIRY_SIZE;
  102.         inquiryCmdBlock.dataToDevice = FALSE;
  103.         status =  DevScsiSendCmdSync(handle, &inquiryCmdBlock, 
  104.                 &(handle->inquiryLength));
  105.         if (status != SUCCESS) {
  106.         if (status == DEV_NO_DEVICE) {
  107.             return (ScsiDevice *) NIL;
  108.         } else {
  109.             handle->inquiryLength = 0;
  110.         }
  111.         }
  112.         tryNumber++;
  113.     }
  114.     }
  115.     if (handle != (ScsiDevice *) NIL) {
  116.     handle->referenceCount++;
  117.     }
  118.     return handle;
  119. }
  120.  
  121. /*
  122.  * The following structure and routine are used to implement DevScsiSendCmdSync.
  123.  * The arguments to DevScsiSendCmdSync are stored in a SyncCmdBuf on 
  124.  * the caller's stack and DevScsiSendCmd is called. The call back function
  125.  * scsiDoneProc fills in the OUT arguments are wakes the caller.
  126.  *
  127.  */
  128. typedef struct SyncCmdBuf {
  129.     Sync_Semaphore mutex;      /* Lock for synronizing updates of 
  130.                    * this structure with the call back 
  131.                    * function. */
  132.     Sync_Condition wait;      /* Condition valued used to wait for
  133.                    * callback. */
  134.     Boolean      done;          /* Is the operation finished or not? */
  135.     int         *statusBytePtr; /* Area to store SCSI status byte. */
  136.     int          *senseBufferLenPtr; /* Sense buffer length pointer. */
  137.     Address    senseBufferPtr;      /* Sense buffer. */
  138.     ReturnStatus status;         /* HBA error for command. */
  139.     int           *countPtr;      /* Btes transferred pointer. */
  140. } SyncCmdBuf;
  141.  
  142. /*
  143.  *----------------------------------------------------------------------
  144.  *
  145.  * scsiDoneProc --
  146.  *
  147.  *    This procedure is called when a scsi command started by 
  148.  *    DevScsiSendCmdSync finished. It's calling sequence is 
  149.  *    defined by the call back done by the DevScsiSendCmd routine.
  150.  *
  151.  * Results:
  152.  *    None
  153.  *
  154.  * Side effects:
  155.  *    A scsi command is executed.
  156.  *
  157.  *----------------------------------------------------------------------
  158.  */
  159.  
  160. static int
  161. scsiDoneProc(scsiCmdPtr, errorCode, statusByte, byteCount, 
  162.          senseDataLen, senseDataPtr)
  163.     ScsiCmd    *scsiCmdPtr;
  164.     ReturnStatus errorCode;
  165.     unsigned char statusByte;
  166.     int        byteCount;
  167.     int        senseDataLen;
  168.     Address    senseDataPtr;
  169. {
  170.     SyncCmdBuf    *syncCmdDataPtr = (SyncCmdBuf *) (scsiCmdPtr->clientData);
  171.     /*
  172.      * A pointer to a SyncCmdBuf is passed as the clientData to this call.
  173.      * Lock the structure, fill in the return values and wake up the
  174.      * initiator.
  175.      */
  176.     MASTER_LOCK(&syncCmdDataPtr->mutex);
  177.  
  178.     *(syncCmdDataPtr->statusBytePtr) = (int) statusByte;
  179.     syncCmdDataPtr->status = errorCode;
  180.     *(syncCmdDataPtr->countPtr) = byteCount;
  181.     if (syncCmdDataPtr->senseBufferLenPtr != (int *) NIL) {
  182.     int    len;
  183.     len = *(syncCmdDataPtr->senseBufferLenPtr);
  184.     if (senseDataLen < len) {
  185.         len = senseDataLen;
  186.     }
  187.     bcopy(senseDataPtr, syncCmdDataPtr->senseBufferPtr, len);            *(syncCmdDataPtr->senseBufferLenPtr) = len;
  188.     }
  189.     syncCmdDataPtr->done = TRUE;
  190.     Sync_MasterBroadcast(&syncCmdDataPtr->wait);
  191.     MASTER_UNLOCK(&syncCmdDataPtr->mutex);
  192.     return (0);
  193.  
  194. }
  195.  
  196. /*
  197.  *----------------------------------------------------------------------
  198.  *
  199.  * DevScsiSendCmdSync --
  200.  *
  201.  *    Send a SCSI command block to the device specified in the 
  202.  *    ScsiDevice. This is the synchronous version that waits
  203.  *    for the status byte and sense data before returning.
  204.  *
  205.  * Results:
  206.  *    A ReturnStatus
  207.  *
  208.  * Side effects: 
  209.  *    A SCSI command block is sent to the device.  
  210.  *
  211.  *----------------------------------------------------------------------
  212.  *
  213.  */
  214. ReturnStatus
  215. DevScsiSendCmdSync(scsiDevicePtr, scsiCmdPtr, amountTransferredPtr)
  216.     ScsiDevice *scsiDevicePtr;  /* Handle for target device. */
  217.     ScsiCmd    *scsiCmdPtr;            /* SCSI command to be sent. */
  218.     int        *amountTransferredPtr; /* OUT - Nuber of bytes transferred. */
  219. {
  220.     ReturnStatus status;
  221.     SyncCmdBuf     syncCmdData;
  222.  
  223.     scsiCmdPtr->clientData = (ClientData) &syncCmdData;
  224.     scsiCmdPtr->doneProc = scsiDoneProc;
  225.     scsiCmdPtr->senseLen = sizeof(scsiCmdPtr->senseBuffer);
  226.     Sync_SemInitDynamic((&syncCmdData.mutex),"ScsiSyncCmdMutex");
  227.     syncCmdData.done = FALSE;
  228.     syncCmdData.statusBytePtr = &scsiCmdPtr->statusByte;
  229.     syncCmdData.senseBufferPtr = (Address) scsiCmdPtr->senseBuffer;
  230.     syncCmdData.senseBufferLenPtr = &scsiCmdPtr->senseLen;
  231.     syncCmdData.countPtr = amountTransferredPtr;
  232.     DevScsiSendCmd(scsiDevicePtr, scsiCmdPtr);
  233.     MASTER_LOCK((&syncCmdData.mutex));
  234.     while (syncCmdData.done == FALSE) { 
  235.     Sync_MasterWait((&syncCmdData.wait),(&syncCmdData.mutex),FALSE);
  236.     }
  237.     MASTER_UNLOCK((&syncCmdData.mutex));
  238.     status = syncCmdData.status;
  239.     Sync_SemClear(&syncCmdData.mutex);
  240.     if ((status == SUCCESS) && (scsiCmdPtr->statusByte != 0) &&
  241.     (scsiDevicePtr->errorProc != (ReturnStatus (*)()) NIL)) {
  242.     status = (scsiDevicePtr->errorProc)(scsiDevicePtr, scsiCmdPtr);
  243.     }
  244.     return status;
  245. }
  246.  
  247.  
  248.  
  249. /*
  250.  *----------------------------------------------------------------------
  251.  *
  252.  * DevScsiSendCmd --
  253.  *
  254.  *    Send a SCSI command block to the device specified in the 
  255.  *    ScsiDevice.
  256.  *
  257.  * Results:
  258.  *    Nothing
  259.  *
  260.  * Side effects: 
  261.  *    A SCSI command block enqueue for the device.  The doneProc procedure
  262.  *    is call upon SCSI command completion.
  263.  *
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * Due to the simplity of this routine and as an attempt to reduce procedure
  267.  * calling depth, this routine is coded as a macro and can be found in
  268.  * scsiHBAInt.h. 
  269.  */
  270. #ifndef DevScsiSendCmd
  271. void 
  272. DevScsiSendCmd(scsiDevicePtr, scsiCmdPtr)
  273.     ScsiDevice       *scsiDevicePtr;      /* Handle for target device. */
  274.     ScsiCmd         *scsiCmdPtr;        /* Command to be executed. */
  275. {
  276.      Dev_QueueInsert(scsiDevicePtr->devQueue, (List_Links *) scsiCmdPtr);
  277. }
  278. #endif /* DevScsiSendCmd */
  279.  
  280.  
  281. /*
  282.  *----------------------------------------------------------------------
  283.  *
  284.  * DevScsiReleaseDevice --
  285.  *
  286.  *     Release a device previously attached with ScsiAttachDevice().
  287.  *
  288.  * Results:
  289.  *    A ReturnStatus.
  290.  *
  291.  * Side effects: 
  292.  *    Unknown.
  293.  *
  294.  *----------------------------------------------------------------------
  295.  */
  296. ReturnStatus 
  297. DevScsiReleaseDevice(scsiDevicePtr)
  298.     ScsiDevice *scsiDevicePtr;  /* Handle for device to be released. */
  299. {
  300.     scsiDevicePtr->referenceCount--;
  301.     if (scsiDevicePtr->referenceCount == 0) { 
  302.     free(scsiDevicePtr->inquiryDataPtr);
  303.     scsiDevicePtr->inquiryDataPtr = (char *) 0;
  304.     scsiDevicePtr->inquiryLength = 0;
  305.     }
  306.     return ((scsiDevicePtr->releaseProc)(scsiDevicePtr));
  307. }
  308.  
  309.  
  310. /*
  311.  *----------------------------------------------------------------------
  312.  *
  313.  *  DevScsiGetSenseCmd --
  314.  *
  315.  *     Procedure for formatting REQUEST SENSE.
  316.  *
  317.  * Results:
  318.  *    void
  319.  *
  320.  * Side effects: 
  321.  *    Unknown.
  322.  *
  323.  *----------------------------------------------------------------------
  324.  */
  325. void
  326. DevScsiSenseCmd(scsiDevicePtr, bufferSize, buffer, scsiCmdPtr)
  327.     ScsiDevice *scsiDevicePtr;  /* Handle for device to be released. */
  328.     int        bufferSize;    /* Size of request sense data buffer. */
  329.     char    *buffer;    /* Data buffer to put sense data. */
  330.     ScsiCmd    *scsiCmdPtr;    /* Scsi command buffer to fill in. */
  331. {
  332.     DevScsiGroup0Cmd(scsiDevicePtr, SCSI_REQUEST_SENSE, 0, 
  333.             (unsigned) bufferSize, scsiCmdPtr);
  334.     scsiCmdPtr->dataToDevice = FALSE;
  335.     scsiCmdPtr->bufferLen = bufferSize;
  336.     scsiCmdPtr->buffer = buffer;
  337. }
  338.  
  339. /*
  340.  *----------------------------------------------------------------------
  341.  *
  342.  *  DevScsiTestReady --
  343.  *
  344.  *     Test to see if a SCSI device is ready.
  345.  *
  346.  * Results:
  347.  *    
  348.  *
  349.  * Side effects: 
  350.  *    A TEST_UNIT_READY command is set to the device.
  351.  *
  352.  *----------------------------------------------------------------------
  353.  */
  354. ReturnStatus
  355. DevScsiTestReady(scsiDevicePtr)
  356.     ScsiDevice *scsiDevicePtr;  /* Handle for device to be released. */
  357. {
  358.     ScsiCmd    unitReadyCmd;    /* Scsi command buffer to fill in. */
  359.     ReturnStatus status;
  360.     int        len;
  361.  
  362.     DevScsiGroup0Cmd(scsiDevicePtr,SCSI_TEST_UNIT_READY, 0, 0, &unitReadyCmd);
  363.     unitReadyCmd.bufferLen = 0;
  364.     len = 0;
  365.     status = DevScsiSendCmdSync(scsiDevicePtr,&unitReadyCmd, &len);
  366.     return status;
  367. }
  368. /*
  369.  *----------------------------------------------------------------------
  370.  *
  371.  *  DevScsiStartStopUnit --
  372.  *
  373.  *     Test to see if a SCSI device is ready.
  374.  *
  375.  * Results:
  376.  *    
  377.  *
  378.  * Side effects: 
  379.  *    A TEST_UNIT_READY command is set to the device.
  380.  *
  381.  *----------------------------------------------------------------------
  382.  */
  383. ReturnStatus
  384. DevScsiStartStopUnit(scsiDevicePtr, start)
  385.     ScsiDevice *scsiDevicePtr;  /* Handle for device to be released. */
  386.     Boolean start;
  387. {
  388.     ScsiCmd        scsiCmd;    /* Scsi command buffer to fill in. */
  389.     ScsiStartStopCmd     *cmdPtr;
  390.     ReturnStatus     status;
  391.     int            len;
  392.  
  393.     bzero((char *) &scsiCmd, sizeof(ScsiCmd));
  394.     scsiCmd.commandBlockLen = sizeof(ScsiStartStopCmd);
  395.     scsiCmd.bufferLen = 0;
  396.     cmdPtr = (ScsiStartStopCmd *) scsiCmd.commandBlock;
  397.     cmdPtr->command = SCSI_START_STOP;
  398.     cmdPtr->unitNumber = scsiDevicePtr->LUN;
  399.     cmdPtr->immed = 0;
  400.     cmdPtr->loadEject = 0;
  401.     cmdPtr->start = (start == TRUE) ? 1 : 0;
  402.     len = 0;
  403.     status = DevScsiSendCmdSync(scsiDevicePtr,&scsiCmd, &len);
  404.     return status;
  405. }
  406.  
  407. /*
  408.  *----------------------------------------------------------------------
  409.  *
  410.  *  DevScsiReadBlockLimits --
  411.  *
  412.  *     Send a Read Block Limits command to the device.
  413.  *
  414.  * Results:
  415.  *    
  416.  *
  417.  * Side effects: 
  418.  *    A SCSI_READ_BLOCK_LIMITS command is set to the device.
  419.  *
  420.  *----------------------------------------------------------------------
  421.  */
  422. ReturnStatus
  423. DevScsiReadBlockLimits(scsiDevicePtr, minPtr, maxPtr)
  424.     ScsiDevice     *scsiDevicePtr; /* Handle for device to be released. */
  425.     int        *minPtr;    /* Minimum block size. */
  426.     int        *maxPtr;    /* Max block size. */
  427. {
  428.     ScsiCmd        cmd;    /* Scsi command buffer to fill in. */
  429.     ReturnStatus     status = SUCCESS;
  430.     int            len;
  431.     ScsiBlockLimits    limits;
  432.  
  433.     DevScsiGroup0Cmd(scsiDevicePtr,SCSI_READ_BLOCK_LIMITS, 0, 0, &cmd);
  434.     cmd.dataToDevice = FALSE;
  435.     cmd.bufferLen = sizeof(ScsiBlockLimits);
  436.     cmd.buffer = (char *) &limits;
  437.     len = 0;
  438.     status = DevScsiSendCmdSync(scsiDevicePtr,&cmd, &len);
  439.     *maxPtr = ((unsigned int) limits.max2 << 16) | 
  440.         ((unsigned int) limits.max1 << 8) | 
  441.         limits.max0;
  442.     *minPtr = (limits.min1 << 8) | limits.min0;
  443.     return status;
  444. }
  445.  
  446.  
  447. /*
  448.  *----------------------------------------------------------------------
  449.  *
  450.  *  DevScsiModeSense --
  451.  *
  452.  *     Send a Mode Sense command to the device.
  453.  *
  454.  * Results:
  455.  *    
  456.  *
  457.  * Side effects: 
  458.  *    A SCSI_READ_BLOCK_LIMITS command is set to the device.
  459.  *
  460.  *----------------------------------------------------------------------
  461.  */
  462. ReturnStatus
  463. DevScsiModeSense(scsiDevicePtr, disableBlockDesc, pageControl, pageCode, 
  464.         vendor, sizePtr, bufferPtr)
  465.     ScsiDevice     *scsiDevicePtr;     /* Handle for device to be released. */
  466.     int        disableBlockDesc;    /* Disable block descriptor field */
  467.     int        pageControl;        /* Page control field. */
  468.     int        pageCode;        /* Page code field. */
  469.     int        vendor;            /* Vendor unique field. */
  470.     int        *sizePtr;        /* Size of buffer/data returned. */
  471.     char    *bufferPtr;        /* Buffer for mode sense data. */
  472. {
  473.     ReturnStatus     status = SUCCESS;
  474.     int            len;
  475.     ScsiCmd        scsiCmd;    /* Scsi command buffer to fill in. */
  476.     ScsiModeSenseCmd     *cmdPtr;
  477.  
  478.     bzero((char *) &scsiCmd, sizeof(ScsiCmd));
  479.     scsiCmd.commandBlockLen = sizeof(ScsiModeSenseCmd);
  480.     scsiCmd.dataToDevice = FALSE;
  481.     scsiCmd.bufferLen = *sizePtr;
  482.     scsiCmd.buffer = bufferPtr;
  483.     cmdPtr = (ScsiModeSenseCmd *) scsiCmd.commandBlock;
  484.     cmdPtr->command = SCSI_MODE_SENSE;
  485.     cmdPtr->unitNumber = scsiDevicePtr->LUN;
  486.     cmdPtr->disableBlockDesc = disableBlockDesc;
  487.     cmdPtr->pageControl = pageControl;
  488.     cmdPtr->pageCode = pageCode;
  489.     cmdPtr->allocLen = *sizePtr;
  490.     cmdPtr->vendor = vendor;
  491.     len = 0;
  492.     status = DevScsiSendCmdSync(scsiDevicePtr,&scsiCmd, &len);
  493.     *sizePtr = len;
  494.     return status;
  495. }
  496.  
  497.  
  498. /*
  499.  *----------------------------------------------------------------------
  500.  *
  501.  *  DevScsiRequestSense --
  502.  *
  503.  *     Send a Request Sense command to the device.
  504.  *
  505.  * Results:
  506.  *    
  507.  *
  508.  * Side effects: 
  509.  *    A SCSI_REQUEST_SENSE command is set to the device.
  510.  *
  511.  *----------------------------------------------------------------------
  512.  */
  513. ReturnStatus
  514. DevScsiRequestSense(scsiDevicePtr, clearCount, vendor, sizePtr, 
  515.     bufferPtr)
  516.     ScsiDevice     *scsiDevicePtr;     /* Handle for device to be released. */
  517.     int        clearCount;        /* Clear counters field. */
  518.     int        vendor;            /* Vendor unique field. */
  519.     int        *sizePtr;        /* Size of buffer/data returned. */
  520.     char    *bufferPtr;        /* Buffer for mode sense data. */
  521. {
  522.     ReturnStatus     status = SUCCESS;
  523.     int            len;
  524.     ScsiCmd        scsiCmd;    /* Scsi command buffer to fill in. */
  525.     ScsiRequestSenseCmd     *cmdPtr;
  526.  
  527.     bzero((char *) &scsiCmd, sizeof(ScsiCmd));
  528.     scsiCmd.commandBlockLen = sizeof(ScsiRequestSenseCmd);
  529.     scsiCmd.dataToDevice = FALSE;
  530.     scsiCmd.bufferLen = *sizePtr;
  531.     scsiCmd.buffer = bufferPtr;
  532.     cmdPtr = (ScsiRequestSenseCmd *) scsiCmd.commandBlock;
  533.     cmdPtr->command = SCSI_REQUEST_SENSE;
  534.     cmdPtr->unitNumber = scsiDevicePtr->LUN;
  535.     cmdPtr->allocLen = *sizePtr;
  536.     cmdPtr->clearCount = clearCount;
  537.     cmdPtr->vendor = vendor;
  538.     len = 0;
  539.     status = DevScsiSendCmdSync(scsiDevicePtr,&scsiCmd, &len);
  540.     *sizePtr = len;
  541.     return status;
  542. }
  543.  
  544.  
  545. /*
  546.  *----------------------------------------------------------------------
  547.  *
  548.  *  DevScsiReadPosition --
  549.  *
  550.  *     Send a Read Position command to the device.
  551.  *
  552.  * Results:
  553.  *    
  554.  *
  555.  * Side effects: 
  556.  *    A SCSI_READ_POSITION command is set to the device.
  557.  *
  558.  *----------------------------------------------------------------------
  559.  */
  560. ReturnStatus
  561. DevScsiReadPosition(scsiDevicePtr, blockType, positionPtr)
  562.     ScsiDevice     *scsiDevicePtr;     /* Handle for device to be released. */
  563.     int        blockType;        /* Block type field. */
  564.     ScsiReadPositionResult *positionPtr; /* Position information. */
  565. {
  566.     ReturnStatus     status = SUCCESS;
  567.     int            len;
  568.     ScsiCmd        scsiCmd;    /* Scsi command buffer to fill in. */
  569.     ScsiReadPositionCmd     *cmdPtr;
  570.  
  571.     bzero((char *) &scsiCmd, sizeof(ScsiCmd));
  572.     scsiCmd.commandBlockLen = sizeof(ScsiReadPositionCmd);
  573.     scsiCmd.dataToDevice = FALSE;
  574.     scsiCmd.bufferLen = sizeof(ScsiReadPositionResult);
  575.     scsiCmd.buffer = (char *) positionPtr;
  576.     cmdPtr = (ScsiReadPositionCmd *) scsiCmd.commandBlock;
  577.     cmdPtr->command = SCSI_READ_POSITION;
  578.     cmdPtr->unitNumber = scsiDevicePtr->LUN;
  579.     cmdPtr->blockType = blockType;
  580.     len = 0;
  581.     status = DevScsiSendCmdSync(scsiDevicePtr,&scsiCmd, &len);
  582.     return status;
  583. }
  584.  
  585.  
  586.  
  587.  
  588. /*
  589.  *----------------------------------------------------------------------
  590.  *
  591.  * DevScsiIOControl --
  592.  *
  593.  *    Process a generic SCSI device IOControl.
  594.  *
  595.  * Results:
  596.  *    The return status of the IOControl.
  597.  *
  598.  * Side effects:
  599.  *    Many.
  600.  *
  601.  *----------------------------------------------------------------------
  602.  */
  603. /*ARGSUSED*/
  604. ReturnStatus
  605. DevScsiIOControl(devPtr, ioctlPtr, replyPtr)
  606.     ScsiDevice    *devPtr;    /* SCSI Handle for device. */
  607.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  608.     Fs_IOReply *replyPtr;    /* Size of outBuffer and returned signal */
  609. {
  610.     ReturnStatus    status;
  611.  
  612.     if (ioctlPtr->command == IOC_SCSI_COMMAND) {
  613.     Dev_ScsiCommand     *cmdPtr;
  614.     Dev_ScsiStatus     *statusPtr;
  615.     ScsiCmd         scsiCmd;
  616.     Boolean        dataToDevice;
  617.     int        senseBufLen;
  618.     /*
  619.      * The user wants to send a SCSI command. First validate
  620.      * the input buffer is large enough to have the parameter
  621.      * block and the output buffer can hold the return status.
  622.      */
  623.     if ((ioctlPtr->inBufSize < sizeof(Dev_ScsiCommand)) ||
  624.         (ioctlPtr->outBufSize < sizeof(Dev_ScsiStatus))) {
  625.         return(GEN_INVALID_ARG);
  626.     }
  627.     cmdPtr = (Dev_ScsiCommand *) ioctlPtr->inBuffer;
  628.     /*
  629.      * Validate the SCSI command block.
  630.      */
  631.     if ((cmdPtr->commandLen < 0) || (cmdPtr->commandLen > 16) ||
  632.         (cmdPtr->commandLen > 
  633.         (ioctlPtr->inBufSize-sizeof(Dev_ScsiCommand))))    {
  634.         return(GEN_INVALID_ARG);
  635.     }
  636.     /*
  637.      * Validate the input or output data buffer.
  638.      */
  639.     dataToDevice = (cmdPtr->dataOffset < ioctlPtr->inBufSize);
  640.     if ((cmdPtr->bufferLen < 0) ||
  641.         (cmdPtr->bufferLen > devPtr->maxTransferSize)) {
  642.         return FS_BUFFER_TOO_BIG;
  643.     }
  644.     if (dataToDevice && 
  645.         (cmdPtr->bufferLen > (ioctlPtr->inBufSize - cmdPtr->dataOffset))) {
  646.         return (GEN_INVALID_ARG);
  647.     }
  648.     if (!dataToDevice && 
  649.        (cmdPtr->bufferLen > (ioctlPtr->outBufSize-sizeof(Dev_ScsiStatus)))){
  650.         return (GEN_INVALID_ARG);
  651.     }
  652.     /*
  653.      * Things look ok. Fill in the ScsiCmd for the device.
  654.      */
  655.     scsiCmd.dataToDevice = dataToDevice;
  656.     scsiCmd.bufferLen = cmdPtr->bufferLen;
  657.     scsiCmd.buffer = dataToDevice ? 
  658.                 (ioctlPtr->inBuffer+cmdPtr->dataOffset) :
  659.                 (ioctlPtr->outBuffer + sizeof(Dev_ScsiStatus));
  660.  
  661.     scsiCmd.commandBlockLen = cmdPtr->commandLen;
  662.     bcopy(ioctlPtr->inBuffer+sizeof(Dev_ScsiCommand), scsiCmd.commandBlock,
  663.           scsiCmd.commandBlockLen);
  664.     statusPtr = (Dev_ScsiStatus *) ioctlPtr->outBuffer;
  665.     status = DevScsiSendCmdSync(devPtr, &scsiCmd, 
  666.             &(statusPtr->amountTransferred));
  667.     statusPtr->statusByte = scsiCmd.statusByte;
  668.         statusPtr->senseDataLen = scsiCmd.senseLen;
  669.     senseBufLen = (ioctlPtr->outBufSize - sizeof(Dev_ScsiStatus) - 
  670.             statusPtr->amountTransferred);
  671.         if (senseBufLen > statusPtr->senseDataLen) {
  672.         senseBufLen = statusPtr->senseDataLen;
  673.     }
  674.     if (senseBufLen >= 0) {
  675.         bcopy(scsiCmd.senseBuffer, 
  676.             (char *)(ioctlPtr->outBuffer + sizeof(Dev_ScsiStatus)
  677.                      + statusPtr->amountTransferred),
  678.                      senseBufLen);
  679.     }
  680.     return status;
  681.     } else {
  682.     return GEN_INVALID_ARG;
  683.     }
  684.  
  685. }
  686.  
  687. /*
  688.  *----------------------------------------------------------------------
  689.  *
  690.  * DevNoHBAAttachDevice --
  691.  *
  692.  *    A SCSI HBA attach procedure that always returns no device. This
  693.  *    routine should be inserted into attach procedure for HBA types
  694.  *    that aren't support on the machine.
  695.  *
  696.  * Results:
  697.  *    NIL 
  698.  *
  699.  * Side effects:
  700.  *
  701.  *----------------------------------------------------------------------
  702.  */
  703. /*ARGSUSED*/
  704. ScsiDevice *
  705. DevNoHBAAttachDevice(devicePtr, insertProc)
  706.     Fs_Device    *devicePtr;    /* Device to attach. */
  707.     void     (*insertProc)(); /* Insert procedure to use. */
  708. {
  709.     return (ScsiDevice *) NIL;
  710. }
  711.